package jwanalytics.agentbasedsimulations;

import sim.engine.SimState;
import sim.field.grid.IntGrid2D;

/** THis is the mason simulation itself.  For details on mason see: http://www.cs.gmu.edu/~eclab/projects/mason/. 
 * It simulates 400 queues of visitors to the site.  Each queue is constantly busy with visitors/agents with a
 * single profile.  So when one visitor is done with browsing the site another visitor with the same profile is
 * recreated on this queue without delay.  You could model delays in between users on a queue using a Poisson
 * distribution but this would defeat the purpose of having a simple example and adds nothing to the demo of an
 * optimization.
 *
 * @author Andre Augusto Cesta
 */
public class BuiltInSimulation extends SimState {

	/**
	 * This describes the pages the user can be at on the simulation.
	 * These pages are also pictured sitemap style on: http://code.google.com/p/jwanalytics/wiki/Optimisation
	 * The colour of the pages (the last one being orange although not perhaps very clear from the image) are
	 * reflected on the simulation grid.  The agents which emulate web site visitors start blue (cold colour)
	 * on the site1.jsp page and as they approach the goal page the become warmer and warmer (green, yellow, orange finally).
	 * 
	 * I've avoided defining these constants, enums and data on jwanalytcsWeb (java web app) as I do not want to
	 * make jwanalyticsAgentBasedSimulations depend at all on the website source code it is testing.
	 * 
	 * The only dependency between the simulation and the site is via the web pages served in this case.
	 */
	public enum SimulationWebPage {
	   //0,      1,     2,          3,       4,        5,        6,       7       (Eg.none.ordinal())
	   //black,  blue,  green,      yellow,  yellow,   yellow,   orange,  black   (BuiltInSimulationGUI.SimulationWebPageColours[none.ordinal()])
		none,    site1, activities, page1,   page2,    page3,    goal,   unknown;
		
		public static SimulationWebPage stringToEnum( String name ) {
			try {
				return valueOf(name);		
			} catch (Exception e) { 	
				return SimulationWebPage.unknown;	
			}
		}		
	}
	
	
	/** Grid for displaying PersonAgent states as integers. */
	public IntGrid2D grid;
	
	/** Matrix of same dimensions as grid above for storing fixed agents. Each cell will be a queue of visitors with the same profile.
	 * It is actually a single visitor which browses the site and then when it is done with browsing the site is reset and starts again. */
	public WebSiteVisitorAgent[][] agents;
	
	/** Width dimension of grid.  20x20 grid, so 400 types of visitors to learn from. */
	public int gridWidth = 20;
	
	/** Height dimension of grid. 20x20 grid, so 400 types of visitors to learn from. */
	public int gridHeight = 20;
	
	/**
	 * This is a web site browsing simulation. So here we have the protocol and host of the site being browsed by the simulation agents.
	 * The site is provided by jwanalyticsWeb module.  It normally runs on http://localhost:8080
	 */
	public String protocolAndHost;
	
	/** 
	 * Creates it with a seed value so simulation can be repeated with same seed and same results if
	 * using deterministic model inside it. 
	 */
	public BuiltInSimulation(long seed, String protocolAndHost) {
		super(seed);		
		this.protocolAndHost = protocolAndHost;
	}
	

	/** Seed grid with agents and their state. */
    void seedGrid() {
        for(int x=0;x<grid.getWidth();x++)
        	for(int y=0;y<grid.getHeight();y++) {
        		//whole field with PersonAgent(s)
        		agents[x][y] = new WebSiteVisitorAgent(protocolAndHost);
        		grid.field[x][y] = agents[x][y].getPageCode().ordinal(); //Not in vacation state.  In vacation state will be 1.
        	}
    }
    
    
    /** Part of mason. */
    public void start() {
    	super.start();  // very important!  This resets and cleans out the Schedule.
    	grid = new IntGrid2D(gridWidth, gridHeight);
    	agents = new WebSiteVisitorAgent[gridWidth][gridHeight];
    	seedGrid();
    	schedule.scheduleRepeating(new WebSiteVisitorCellAutomata()); //schedule Cell Automata singleton.
    }	
    
    
    /** 
     * Simulation can be run via this method without a graphical user interface (more performant). 
     * @param args args[0] should contain the protocol and host.
     */
    public static void main(String[] args) {
    	//Seed it with current time.
    	BuiltInSimulation builtInSimulation = new BuiltInSimulation(System.currentTimeMillis(), args[0]); //args[0] should contain the protocol and host.
    	builtInSimulation.start();
    	long steps = 0;
    	do {
    		if (!builtInSimulation.schedule.step(builtInSimulation))
    			break;
    		steps = builtInSimulation.schedule.getSteps();
            if (steps % 500 == 0) {
                System.out.println("Steps: " + steps + " Time: " + builtInSimulation.schedule.time());
            }    		
        } while(steps < 5000);
    	builtInSimulation.finish();
    	System.exit(0);  // make sure any threads finish up
    }
    
    
}


    
